#include "MsgHandler/include/CustomHandler.h"

static const int BLOCK_SIZE=256;

CustomStrategy* CustomStrategyFactory::createStrategy(const std::string type)
{
    if(type=="signup"){
        return new SignUpStrategy();
    }else if(type=="updateuseravatar")
    {
        return new UpdateAvatarStrategy();
    }
    return nullptr;
}




void SignUpStrategy::execute(int socket, std::vector<std::string> *content) const
{

    std::string useroc=content->at(2);
    std::cout<<"signup useroc -> "<<useroc<<std::endl;
    //构造头像存放路径
    std::string file_name="./Avatar/";
    file_name.append(useroc);
    file_name.append(".png");

    //获取user数据库连接
    auto conn_set=SqlSetManager::getInstance()->getSet("user");
    auto conn = conn_set->acquire();

    //检查是否已存在该用户oc
    std::string query_exist="SELECT passwd FROM userinfo WHERE useroc=?";
    auto res=conn->preExecute(query_exist,useroc);
    //有结果代表存在该oc了
    if(res->next())
    {
        std::string json;
        JsonEncoder::getInstance().ErrorMsg(json,ErrorType::OC_CONFLICT);
        TcpServer::sendMsg(socket,json);

        conn->freeRes();
        conn_set->release(conn);
        delete content;
        return;
    }


    //创建用户数据库


    try
    {


        conn->startTransaction();
        conn->executeVoid(fmt::format("CREATE DATABASE {};",useroc));
        conn->executeVoid(fmt::format("USE {};",useroc));
        conn->executeVoid("CREATE TABLE chat_tmp("
                      "id INT PRIMARY KEY AUTO_INCREMENT,"
                      "sender VARCHAR(255) NOT NULL,"
                      "content VARCHAR(1024) NOT NULL"
                      ");");
        conn->executeVoid("CREATE TABLE friendlist("
                      "friendoc VARCHAR(255) PRIMARY KEY NOT NULL"
                      ");");
        conn->executeVoid("CREATE TABLE friendapply("
                      "targetoc VARCHAR(255) PRIMARY KEY NOT NULL,"
                      "apply_status TINYINT(1) NOT NULL"
                      ");");
        conn->executeVoid("CREATE TABLE friendapply_tmp("
                      "targetoc VARCHAR(255) PRIMARY KEY NOT NULL,"
                      "apply_status TINYINT(1) NOT NULL"
                      ");");
        conn->executeVoid("CREATE TABLE contactlist("
                      "useroc VARCHAR(255) PRIMARY KEY NOT NULL"
                      ");");
        conn->commit();
        conn->setCurDB("user");

    } catch (const std::runtime_error& e) {
        std::string json;
        JsonEncoder::getInstance().ErrorMsg(json,ErrorType::OC_CONFLICT);
        std::cout<<"create db failed"<<std::endl;
        TcpServer::sendMsg(socket,json);
        delete content;
        std::cout<<e.what()<<std::endl;
        conn->freeRes();
        conn_set->release(conn);

        return;
    }

    std::string query= "INSERT INTO userinfo(useroc,passwd,user_name,avatar_path,user_online,user_status) VALUES(?,?,?,?,?,?)";
    std::string db_query= "INSERT INTO dbinfo(useroc,db_name) VALUES(?,?)";

    //插入到userinfo表
    //oc, 密码，昵称,头像路径，user_online,user_status
    std::vector<std::string> sql_value={useroc,content->at(4),content->at(3),file_name,"0","0"};
    try {
        conn->preExecuteVoid(query,sql_value);
        conn->preExecuteVoid(db_query,useroc,useroc);
        OCDatabaseMapper::getInstance()->addOC(useroc,useroc);
    } catch (const std::runtime_error& e) {

        std::cout<<e.what()<<std::endl;
        conn->freeRes();
        conn_set->release(conn);
        delete content;
        return;
    }


    conn->freeRes();
    conn_set->release(conn);


    SqlSetManager::getInstance()->addNewDB(useroc);

    //保存头像到本地
    std::ofstream out_put(file_name,std::ios::binary);
    int total_size=content->at(5).size();
    int write_size=0;
    if(!out_put)
    {
        std::cout<<"open file failed"<<std::endl;
        return;
    }

    int write=BLOCK_SIZE;
    while(write_size<total_size)
    {
        if(total_size-write<2000)
        {
            write=total_size-write;
        }

        out_put.write(content->at(5).data()+write_size,write);
        write_size+=write;
    }
    out_put.close();
    std::string ok;
    JsonEncoder::getInstance().OkMsg(ok,OKType::SIGNUP);
    //std::cout<<"signup"<<std::endl;
    TcpServer::sendMsg(socket,ok);
    delete content;


}

void UpdateAvatarStrategy::execute(int socket, std::vector<std::string> *content) const
{
    std::string useroc=content->at(2);
    auto userinfo_conn_set=SqlSetManager::getInstance()->getSet("user");
    auto userinfo_conn=userinfo_conn_set->acquire();
    auto res=userinfo_conn->preExecute("SELECT avatar_path FROM userinfo WHERE useroc=?",useroc);
    std::string avatar_path;
    if(res->next())
    {
        avatar_path=res->getString(1);
    }
    else
    {
        userinfo_conn_set->release(userinfo_conn);
        delete content;
        return;
    }
    userinfo_conn_set->release(userinfo_conn);

    //保存头像到本地
    std::ofstream out_put(avatar_path,std::ios::binary);
    int total_size=content->at(3).size();
    int write_size=0;
    if(!out_put)
    {
        std::cout<<"open file failed"<<std::endl;
        return;
    }
    int write=BLOCK_SIZE;
    while(write_size<total_size)

    {

        if(total_size-write<2000)
        {
            write=total_size-write;
        }
        out_put.write(content->at(3).data()+write_size,write);
        write_size+=write;
    }
    out_put.close();

    auto user_conn_set=SqlSetManager::getInstance()->getSet(OCDatabaseMapper::getInstance()->getDB(useroc));
    auto user_conn=user_conn_set->acquire();
    res=user_conn->execute("SELECT useroc AS value FROM contactlist UNION SELECT targetoc AS value FROM friendapply WHERE apply_status='0' OR apply_status='3'");

    while(res->next())
    {
        std::string targetoc=res->getString(1);
        //在线
        if(SocketManager::getInstacne()->isAlive(targetoc))
        {
            MsgVector msg;
            msg.createHead("avatarupdate");
            msg.addContent(useroc.c_str(),false);
            int pre_len=msg.length();
            std::ifstream ios(avatar_path,std::ios::binary);
            if(!ios)
            {
                std::cout<<"open file failed"<<std::endl;
                user_conn_set->release(user_conn);
                delete content;
                return;
            }
            ios.seekg(0,std::ios::end);
            std::streamsize file_size=ios.tellg();
            ios.seekg(0,std::ios::beg);
            int read_done=0;
            int block_size=BLOCK_SIZE;

            msg.resize(pre_len+file_size+1);


            while(read_done<file_size)
            {
                if(file_size-read_done<block_size)
                {
                    block_size=file_size-read_done;
                }

                ios.read(msg[read_done+pre_len],block_size);
                read_done+=block_size;
            }
            auto str=msg.getMsg();
            std::cout<<"send new avatar to "<<targetoc<<std::endl;
            int target_socket=SocketManager::getInstacne()->getSocket(targetoc);
            TcpServer::sendMsg(target_socket,*str);
            delete str;
        }
        else//不在线
        {
            auto userinfo_conn_set=SqlSetManager::getInstance()->getSet("user");
            auto userinfo_conn=userinfo_conn_set->acquire();
            auto res=userinfo_conn->preExecute("SELECT id FROM avatarupdate WHERE targetoc=? AND useroc=?",targetoc,useroc);
            if(!res->next())
            {
                userinfo_conn->preExecuteVoid("INSERT INTO avatarupdate(targetoc,useroc) VALUES(?,?) ",targetoc,useroc);
            }
            userinfo_conn_set->release(userinfo_conn);
        }
    }
    user_conn_set->release(user_conn);
}
